package com.wkbb.basic.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wkbb.basic.config.BasicConfig;
import com.wkbb.basic.model.OrgServiceConfig;
import com.wkbb.basic.service.OrgServiceConfigService;
import com.wkbb.basic.service.WebankUtilService;
import com.wkbb.basic.service.XmppService;
import com.wkbb.basic.utils.WebankUtil;
import com.wkbb.basic.utils.FileUtil;
import com.wkbb.common.config.ServiceConfig;
import com.wkbb.common.constants.RedisKeyConstant;
import com.wkbb.common.redis.RedisTemplateUtil;
import com.wkbb.common.utils.HttpClientUtil;
import com.wkbb.common.utils.StringUtil;
import com.wkbb.common.utils.UuIdUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.net.URL;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.wkbb.basic.utils.WebankUtil.ACCESS_TOKEN;


/**
 * @author dengjingyuan
 * @date 2019-07-04 10:32
 */
@Slf4j
@Service
public class WebankUtilServiceImpl implements WebankUtilService {

    @Autowired
    @Lazy
    private XmppService xmppService;
    @Autowired
    private  RedisTemplateUtil redisTemplateUtil;
    @Autowired
    private  ServiceConfig serviceConfig;
    @Autowired
    private  BasicConfig basicConfig;
    @Autowired
    private OrgServiceConfigService orgServiceConfigService;



    @Override
    public  String addGroup(String groupNo, String groupName, Integer groupType, String remark, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        log.info("======Webank======{}", "新增用户组信息");

        return addOrModifyGroup(WebankUtil.ADD_GROUP, groupNo, groupName, groupType, remark, isRetry,webankAppid,webankSecret,orgId);
    }
    @Override
    public  String modifyGroup(String groupNo, String groupName, Integer groupType, String remark, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        log.info("======Webank======{}", "修改用户组信息");

        return addOrModifyGroup(WebankUtil.MODIFY_GROUP, groupNo, groupName, groupType, remark, isRetry,webankAppid,webankSecret,orgId);
    }

    /**
     * 删除用户组信息
     *
     * @param groupNo 组编号
     * @return 操作结果
     */
    @Override
    public  String delGroup(String groupNo, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        log.info("======Webank======{}", "删除用户组信息");

        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }
        jsonBody.put("groupNo", UuIdUtil.getGroupIds(serviceConfig.getProfilesActive(), groupNo));
        return doPost(WebankUtil.DEL_GROUP, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }

    /**
     * 新增或修改用户组信息
     *
     * @param action    操作类型
     * @param groupNo   组编号，同一 appid 下需唯一
     * @param groupName 组名称
     * @param groupType 组类型： 1 一般组， 2 访客组
     * @param remark    备注
     * @return 操作结果
     */
    private  String addOrModifyGroup(String action, String groupNo, String groupName, Integer groupType, String remark, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        //groupNo进行补位
        jsonBody.put("groupNo", UuIdUtil.getGroupIds(serviceConfig.getProfilesActive(), groupNo));
        if (StringUtil.isNotEmptyIgnoreBlank(groupName)) {
            jsonBody.put("groupName", groupName);
        }
        if (groupType != null) {
            jsonBody.put("groupType", groupType);
        }
        if (StringUtil.isNotEmptyIgnoreBlank(remark)) {
            jsonBody.put("remark", remark);
        }

        log.info("----------输出新增用户组入参----------action:{},jsonBody:{},isRetry:{},webankAppid:{},orgId:{}",action, JSONObject.toJSON(jsonBody), isRetry,webankAppid,orgId);

        return doPost(action, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }
    @Override
    public  String addPerson(String userId, String name, String showName, String idType, String idNo, String phoneNo, String photoStr, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        log.info("======Webank======{}", "新增用户信息");

        return addOrModifyPerson(WebankUtil.ADD_PERSON, userId, name, showName, idType, idNo, phoneNo, photoStr, isRetry,webankAppid,webankSecret,orgId);
    }
    @Override
    public  String modifyPerson(String userId, String name, String showName, String idType, String idNo, String phoneNo, String photoStr, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        log.info("======Webank======{}", "修改用户信息");

        return addOrModifyPerson(WebankUtil.MODIFY_PERSON, userId, name, showName, idType, idNo, phoneNo, photoStr, isRetry,webankAppid,webankSecret,orgId);
    }
    @Override
    public  String delPerson(String userId, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        log.info("======Webank======{}", "删除用户信息");

        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        jsonBody.put("userId", userId);
        return doPost(WebankUtil.DEL_PERSON, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }

    /**
     * 新增或修改用户信息
     *
     * @param action   操作类型
     * @param userId   用户编号，同一 appid 下需唯一
     * @param name     姓名
     * @param showName 前端显示名,用户设备上显示的人员名称
     * @param idType   证件类型
     *                 01 身份证
     *                 02 军人军官证
     *                 03 港澳回乡证
     *                 04 中国护照
     *                 07 临时身份证
     *                 08 户口薄
     *                 16 外国护照
     *                 23 港澳居民居住证
     *                 24 台湾居民居住证
     *                 99 其它个人证件
     * @param idNo     证件号
     * @param phoneNo  手机号
     * @param photoStr 人脸图片
     * @return 操作结果
     */
    private  String addOrModifyPerson(String action, String userId, String name, String showName, String idType, String idNo, String phoneNo, String photoStr, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        jsonBody.put("userId", userId);
        jsonBody.put("name", StringUtil.isEmptyIgnoreBlank(name) ? userId : name);
        jsonBody.put("showName", StringUtil.isEmptyIgnoreBlank(showName) ? userId : showName);
        if (StringUtil.isNotEmptyIgnoreBlank(idType)) {
            jsonBody.put("idType", idType);
        }
        if (StringUtil.isNotEmptyIgnoreBlank(idNo)) {
            jsonBody.put("idNo", idNo);
        }
        if (StringUtil.isNotEmptyIgnoreBlank(phoneNo)) {
            jsonBody.put("phoneNo", phoneNo);
        }

        if (null!=orgId) {
            jsonBody.put("groupNoList", manageGroupList(Arrays.asList(orgId)));
        }else{
            return null;
        }

        if (StringUtil.isNotEmptyIgnoreBlank(photoStr)) {
            try {
                jsonBody.put("photoStr", FileUtil.encodeImageToJpgBase64(new URL(photoStr)));
            } catch (Exception e) {
                log.error("=========Webank=========addOrModifyPerson图片转Base64错误:{}", e.getMessage());
                return null;
            }

            try {
                OrgServiceConfig orgServiceConfig = orgServiceConfigService.getOrgConfigByOrgId(orgId);

                if(null!=orgServiceConfig){
                    // 录制他人人脸开关 0：关闭 1：开启 默认关闭
                    Boolean faceOtherPersonFlag = orgServiceConfig.getFaceOtherPersonFlag()==null?false:orgServiceConfig.getFaceOtherPersonFlag();
                    //校验是否本人照片 -阈值设置[0-100]的整数，建议设置
                    //为 60； -如未设置，则系统默认为 0，表示不
                    //校验是否为本人照片
                    if(faceOtherPersonFlag){
                        jsonBody.put("faceMatchThreshold",90);
                    }else{
                        jsonBody.put("faceMatchThreshold",0);
                    }
                }
            }catch (Exception e){
                log.error("----------获取学校配置失败----------orgId:{}",orgId);
            }
        }

        //修改人员信息时,需要查询学校配置(录制他人人脸开关 0：关闭 1：开启 默认关闭)

        return doPost(action, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }

    /**
     * 走腾讯云部署的独立服务完成 新增或修改用户信息
     *
     * @param action   操作类型
     * @param userId   用户编号，同一 appid 下需唯一
     * @param name     姓名
     * @param showName 前端显示名,用户设备上显示的人员名称
     * @param idType   证件类型
     *                 01 身份证
     *                 02 军人军官证
     *                 03 港澳回乡证
     *                 04 中国护照
     *                 07 临时身份证
     *                 08 户口薄
     *                 16 外国护照
     *                 23 港澳居民居住证
     *                 24 台湾居民居住证
     *                 99 其它个人证件
     * @param idNo     证件号
     * @param phoneNo  手机号
     * @param photoUrl 人脸图片
     * @return 操作结果
     */
    private  String addOrModifyPersonByTcThirdService(String action, String userId, String name, String showName, String idType, String idNo, String phoneNo, String photoUrl, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        jsonBody.put("userId", userId);
        jsonBody.put("name", StringUtil.isEmptyIgnoreBlank(name) ? userId : name);
        jsonBody.put("showName", StringUtil.isEmptyIgnoreBlank(showName) ? userId : showName);
        if (StringUtil.isNotEmptyIgnoreBlank(idType)) {
            jsonBody.put("idType", idType);
        }
        if (StringUtil.isNotEmptyIgnoreBlank(idNo)) {
            jsonBody.put("idNo", idNo);
        }
        if (StringUtil.isNotEmptyIgnoreBlank(phoneNo)) {
            jsonBody.put("phoneNo", phoneNo);
        }

        if (null!=orgId) {
            jsonBody.put("groupNoList", manageGroupList(Arrays.asList(orgId)));
        }else{
            return null;
        }

        jsonBody.put("photoStr", photoUrl);

//        if (StringUtil.isNotEmptyIgnoreBlank(photoStr)) {
//            try {
//                jsonBody.put("photoStr", FileUtil.encodeImageToJpgBase64(new URL(photoStr)));
//            } catch (Exception e) {
//                log.error("=========Webank=========addOrModifyPerson图片转Base64错误:{}", e.getMessage());
//                return null;
//            }
//        }

        return doPostByTcThirdService(action, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }

    /**
     * 绑定用户到组
     *
     * @param userId      用户编号
     * @param groupNoList 组编号列表
     * @return 操作结果
     */
    @Override
    public  String setGroups(String userId, List<Object> groupNoList, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        log.info("======Webank======{}", "绑定用户到组");

        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        jsonBody.put("groupNoList", manageGroupList(groupNoList));
        jsonBody.put("userId", userId);

        return doPost(WebankUtil.SET_GROUP, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }

    @Override
    public  String addDevice(String deviceNo, String deviceName, Integer liveSwitch, String location, String remark, List<Object> groupNoList, boolean isRetry, String webankAppid, String webankSecret, Long orgId,Integer cameraType , Integer cameraTypeSwitch) {
        log.info("======Webank======{}", "添加设备信息");

        return addOrModifyDevice(WebankUtil.ADD_DEVICE, deviceNo, deviceName, liveSwitch, location, remark, null, null, groupNoList, isRetry,webankAppid,webankSecret,orgId,cameraType, cameraTypeSwitch);
    }

    @Override
    public  String modifyDevice(String deviceNo, String deviceName, Integer liveSwitch, String location, String remark, String status, String statusSwitch, List<Object> groupNoList, boolean isRetry, String webankAppid, String webankSecret, Long orgId,Integer cameraType , Integer cameraTypeSwitch) {
        log.info("======Webank======{}", "修改设备信息");

        return addOrModifyDevice(WebankUtil.MODIFY_DEVICE, deviceNo, deviceName, liveSwitch, location, remark, status, statusSwitch, groupNoList, isRetry,webankAppid,webankSecret,orgId,cameraType, cameraTypeSwitch);
    }

    @Override
    public  String batchModifyDevice(String deviceNo, Integer cameraType, Integer cameraTypeSwitch, boolean isRetry, String webankAppid, String webankSecret, Long orgId) {
        log.info("======Webank======{}", "批量修改设备信息");

        return batchModifyDevice(WebankUtil.MODIFY_DEVICE, deviceNo, cameraType, cameraTypeSwitch , isRetry,webankAppid,webankSecret,orgId);
    }

    @Override
    public  String getDeviceInfo(String deviceNo, boolean isRetry, String webankAppid, String webankSecret, Long orgId) {
        log.info("======Webank======{}", "查询设备信息");

        return getDeviceInfo(WebankUtil.GET_DEVICE, deviceNo,  isRetry,webankAppid,webankSecret,orgId);
    }

    @Override
    public  String delDevice(String deviceNo, boolean isRetry, String webankAppid, String webankSecret, Long orgId) {
        log.info("======Webank======{}", "删除设备信息");

        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        jsonBody.put("deviceNo", deviceNo);
        return doPost(WebankUtil.DEL_DEVICE, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }

    /**
     * 新增或修改用户信息
     *
     * @param action       操作类型
     * @param deviceNo     设备编号
     * @param deviceName   设备名称
     * @param liveSwitch   活体验证开关 0 关闭 1 开启  对应新接口的cameraTypeSwitch字段，微众做了兼容
     * @param location     设备所在位置
     * @param remark       设备描述
     * @param status       设备状态 0 停用 1 启用
     * @param statusSwitch 重启设备是否需要初始化人脸库
     * @param groupNoList  设备关联组列表
     * @return 操作结果
     */
    private  String addOrModifyDevice(String action, String deviceNo, String deviceName, Integer liveSwitch, String location, String remark, String status, String statusSwitch, List<Object> groupNoList, boolean isRetry,String webankAppid,String webankSecret,Long orgId,Integer cameraType , Integer cameraTypeSwitch) {
        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        jsonBody.put("deviceNo", deviceNo);
        if (StringUtil.isNotEmptyIgnoreBlank(deviceName)) {
            jsonBody.put("deviceName", deviceName);
        }
        if (liveSwitch != null) {
            jsonBody.put("liveSwitch", liveSwitch);
        }
        if (StringUtil.isNotEmptyIgnoreBlank(location)) {
            jsonBody.put("location", location);
        }
        if (StringUtil.isNotEmptyIgnoreBlank(remark)) {
            jsonBody.put("remark", remark);
        }
        if (StringUtil.isNotEmptyIgnoreBlank(status)) {
            jsonBody.put("status", status);
        }
        if (StringUtil.isNotEmptyIgnoreBlank(statusSwitch)) {
            jsonBody.put("statusSwitch", statusSwitch);
        }

        if(cameraType != null) {
            jsonBody.put("cameraType", cameraType);
        }
        if(cameraTypeSwitch != null) {
            jsonBody.put("cameraTypeSwitch", cameraTypeSwitch);
        }


        jsonBody.put("groupNoList", manageGroupList(groupNoList));
        jsonBody.put("recognitionGapThreshold", "00:00-23:59,0.1-26");//设置识别距离

        return doPost(action, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }

    /**
     * 批量修改设备信息
     *
     * @param action       操作类型
     * @param deviceNo     设备编号
     * @param cameraType  摄像头类型，0:红外双目 1:单目
     * @param cameraTypeSwitch  活体开关，0:关闭 1:开启 1) 如果摄像头类型是“红外双目”，则该开关设置的是“红外活体开关” 2) 如果摄像头类型是“1 单目”，则该开关是设置“翻拍活体开关” 3) 如果不传值，则默认红外活体开，翻拍活体关
     * @param isRetry
     * @return 操作结果
     */
    private  String batchModifyDevice(String action, String deviceNo, Integer cameraType , Integer cameraTypeSwitch , boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        jsonBody.put("deviceNo", deviceNo);
        if(cameraType != null) {
            jsonBody.put("cameraType", cameraType);
        }
        if(cameraTypeSwitch != null) {
            jsonBody.put("cameraTypeSwitch", cameraTypeSwitch);
        }
        return doPost(action, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }
    /**
     * 批量修改设备信息
     *
     * @param action       操作类型
     * @param deviceNo     设备编号
     * @param isRetry
     * @return 操作结果
     */
    private  String getDeviceInfo(String action, String deviceNo, boolean isRetry,String webankAppid,String webankSecret,Long orgId ) {
        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        jsonBody.put("deviceNo", deviceNo);

        return doPost(action, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }

    /**
     * 申请appid
     * @param appName  应用名称
     * @param appNo  应用编号 ,通过 appNo 查询已申请的 APPID
     * @param serviceType  应用服务类型        0-试用版的 APPID        1-正式版的 APPID， 二选一        不填则默认为 1 正式版
     * @return 操作结果
     */
    @Override
    public  String getAPPID(String appNo, boolean isRetry, String webankAppid, String webankSecret, Long orgId, String appName, short serviceType, String webankOrgId ) {
        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        jsonBody.put("appNo", appNo);
        jsonBody.put("appName", appName);
        jsonBody.put("serviceType", serviceType);
        jsonBody.put("orgId", webankOrgId);

        return doPost(WebankUtil.APPLY_APP, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }

    /**
     * 查询 APPID
     * @param appNo  应用编号 ,通过 appNo 查询已申请的 APPID
     * @param isRetry
     * @return 操作结果
     */
    @Override
    public  String searchAPPID(String appNo, boolean isRetry, String webankAppid, String webankSecret, Long orgId , String webankOrgId ) {
        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        jsonBody.put("appNo", appNo);
        jsonBody.put("orgId", webankOrgId);
        return doPost(WebankUtil.SEARCH_APP, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }

    /**
     * 1:N在线人脸检索
     *
     * @param image       图片base64，小于5M
     * @param deviceNo    设备编号
     * @param groupNoList 组编号列表
     * @return 检索结果
     */
    @Override
    public  String searchFace(String image, String deviceNo, List<Object> groupNoList, boolean isRetry, String webankAppid, String webankSecret, Long orgId) {
        log.info("======Webank======{}", "1:N在线人脸检索");

        if (groupNoList == null || groupNoList.isEmpty()) {
            return null;
        }

        JSONObject jsonBody = getJsonBody(webankAppid,webankSecret,orgId);
        if (jsonBody == null) {
            return null;
        }

        jsonBody.put("image", image);
        jsonBody.put("groupNoList", manageGroupList(groupNoList));
        if (StringUtil.isNotEmptyIgnoreBlank(deviceNo)) {
            jsonBody.put("deviceNo", deviceNo);
        }

        return doPost(WebankUtil.SEARCH_FACE, jsonBody, isRetry,webankAppid,webankSecret,orgId);
    }

    @Override
    public  List<Object> manageGroupList(List<Object> groupNoList) {
        List<Object> manageGroupList = new ArrayList<>();
        if (groupNoList != null) {
            //groupNo进行补位
            for (Object groupNo : groupNoList) {
                manageGroupList.add(UuIdUtil.getGroupIds(serviceConfig.getProfilesActive(), String.valueOf(groupNo)));
            }
        } else {
            //TODO 若未传入任何组，则将用户移入回收站组（限制100w条数据），之后看业务逻辑可以做毕业组之类的，分担数据量
            manageGroupList.add("trash_group");
        }
        return manageGroupList;
    }

    /**
     * 进行请求
     *
     * @param action   具体操作
     * @param jsonBody 请求内容
     * @param isRetry  是否用之前的token重试请求
     * @return 请求结果
     */
    private  String doPost(String action, JSONObject jsonBody, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        JSONObject logJson = (JSONObject) jsonBody.clone();
        logJson.remove("photoStr");
        log.info("======WebankPost======action:{},params{}", action, logJson.toString());
        long current = System.currentTimeMillis();
        String result = HttpClientUtil.doPostJson(getUrl(action), jsonBody.toString());
        log.info("======WebankPost======cost:{}ms,result:{}", System.currentTimeMillis() - current, result);

        //如果不是重试而且Token过期，刷新token后重试
        if (!isRetry && WebankUtil.TOKEN_TIME_OUT.equals(getCode(result))) {
            String retry = refreshTokenAndRetry(action, jsonBody,webankAppid,webankSecret,orgId);
            if (StringUtil.isNotEmpty(retry)) {
                return retry;
            }
        }

        return result;
    }

    /**
     * 走部署在腾讯云的服务，进行请求
     *
     * @param action   具体操作
     * @param jsonBody 请求内容
     * @param isRetry  是否用之前的token重试请求
     * @return 请求结果
     */
    private  String doPostByTcThirdService(String action, JSONObject jsonBody, boolean isRetry,String webankAppid,String webankSecret,Long orgId) {
        JSONObject logJson = (JSONObject) jsonBody.clone();
        logJson.remove("photoStr");
//        log.info("======WebankPost======action:{},params{}", action, logJson.toString());
        long current = System.currentTimeMillis();
        String result = HttpClientUtil.doPostJson(getTcThirdServiceUrl(action), jsonBody.toString());
        log.info("======WebankPost======params{},cost:{}ms,result:{},url:{}",logJson.toString(), System.currentTimeMillis() - current, result,getTcThirdServiceUrl(action));

        //如果不是重试而且Token过期，刷新token后重试
        if (!isRetry && WebankUtil.TOKEN_TIME_OUT.equals(getCode(result))) {
            String retry = refreshTokenAndRetry(action, jsonBody,webankAppid,webankSecret,orgId);
            if (StringUtil.isNotEmpty(retry)) {
                return retry;
            }
        }

        return result;
    }

    /**
     * 刷新Token后重新请求
     *
     * @param action   具体操作
     * @param jsonBody 请求数据
     * @return 操作结果
     */
    private  String refreshTokenAndRetry(String action, JSONObject jsonBody,String webankAppid,String webankSecret,Long orgId) {
        log.warn("======Webank======Token失效，刷新后重试,orgId:{},weBankAppid:{},webankSecret：{}",  orgId,webankAppid,webankSecret);
        //清除缓存
        redisTemplateUtil.delete(RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid);
        redisTemplateUtil.delete(RedisKeyConstant.WKBB_BASIC_WEBANK_SIGN_TICKET+webankAppid);

        //重新请求
        switch (action) {
            case WebankUtil.ADD_GROUP:
                return addGroup(jsonBody,webankAppid,webankSecret,orgId);
            case WebankUtil.MODIFY_GROUP:
                return modifyGroup(jsonBody,webankAppid,webankSecret,orgId);
            case WebankUtil.DEL_GROUP:
                return delGroup(jsonBody,webankAppid,webankSecret,orgId);
            case WebankUtil.ADD_PERSON:
                return addPerson(jsonBody,webankAppid,webankSecret,orgId);
            case WebankUtil.MODIFY_PERSON:
                return modifyPerson(jsonBody,webankAppid,webankSecret,orgId);
            case WebankUtil.DEL_PERSON:
                return delPerson(jsonBody,webankAppid,webankSecret,orgId);
            case WebankUtil.SET_GROUP:
                return setGroups(jsonBody,webankAppid,webankSecret,orgId);
            case WebankUtil.SEARCH_FACE:
                return searchFace(jsonBody,webankAppid,webankSecret,orgId);
        }

        return null;
    }

    private  String searchFace(JSONObject jsonBody,String webankAppid,String webankSecret,Long orgId) {
        return searchFace(jsonBody.getString(""), jsonBody.getString("deviceNo"),
                jsonBody.getJSONArray("groupNoList").toJavaList(Object.class), true,webankAppid,webankSecret,orgId);
    }

    private  String setGroups(JSONObject jsonBody,String webankAppid,String webankSecret,long orgId) {
        return setGroups(jsonBody.getString("userId"),
                jsonBody.getJSONArray("groupNoList").toJavaList(Object.class), true,webankAppid,webankSecret,orgId);
    }

    private  String delPerson(JSONObject jsonBody,String webankAppid,String webankSecret,Long orgId) {
        return delPerson(jsonBody.getString("userId"), true,webankAppid,webankSecret,orgId);
    }

    private  String modifyPerson(JSONObject jsonBody,String webankAppid,String webankSecret,Long orgId) {
        return modifyPerson(jsonBody.getString("userId"), jsonBody.getString("name"),
                jsonBody.getString("showName"), jsonBody.getString("idType"), jsonBody.getString("idNo"),
                jsonBody.getString("phoneNo"), jsonBody.getString("photoStr"), true,webankAppid,webankSecret,orgId);
    }

    private  String addPerson(JSONObject jsonBody,String webankAppid,String webankSecret,Long orgId) {
        return addPerson(jsonBody.getString("userId"), jsonBody.getString("name"),
                jsonBody.getString("showName"), jsonBody.getString("idType"), jsonBody.getString("idNo"),
                jsonBody.getString("phoneNo"), jsonBody.getString("photoStr"), true,webankAppid,webankSecret,orgId);
    }

    private  String delGroup(JSONObject jsonBody,String webankAppid,String webankSecret,Long orgId) {
        return delGroup(jsonBody.getString("groupNo"), true,webankAppid,webankSecret,orgId);
    }

    private  String modifyGroup(JSONObject jsonBody,String webankAppid,String webankSecret,Long orgId) {
        return modifyGroup(jsonBody.getString("groupNo"), jsonBody.getString("groupName"),
                jsonBody.getInteger("groupType"), jsonBody.getString("remark"), true,webankAppid,webankSecret,orgId);
    }

    private  String addGroup(JSONObject jsonBody,String webankAppid,String webankSecret,Long orgId) {
        return addGroup(jsonBody.getString("groupNo"), jsonBody.getString("groupName"),
                jsonBody.getInteger("groupType"), jsonBody.getString("remark"), true,webankAppid,webankSecret,orgId);
    }

    private  String getSign(String version, String nonce, String orderNo,String webankAppid,String webankSecret,Long orgId) {
        String ticket = getSignTicket(webankAppid,webankSecret,orgId);
        if (StringUtil.isNullOrBlank(ticket)) {
            return null;
        }

        List<String> list = new ArrayList<String>();
        list.add(webankAppid);
        list.add(nonce);
        list.add(version);
        list.add(orderNo);
        list.add(ticket);

        Collections.sort(list);
        StringBuilder str = new StringBuilder();
        for (String s : list) {
            str.append(s);
        }
        return DigestUtils.sha1Hex(str.toString());
    }
    @Override
    public String getSignTicket(String webankAppid, String webankSecret, Long orgId) {
        String signTicket;

        // 如果AccessToken过期，同时也刷新SignTicket
        if (checkAccessToken(webankAppid)) {
            signTicket = (String) redisTemplateUtil.get(RedisKeyConstant.WKBB_BASIC_WEBANK_SIGN_TICKET+webankAppid);
            if (StringUtil.isNotEmptyIgnoreBlank(signTicket)) {
                return signTicket;
            }
        }

        String accessToken = getAccessToken(webankAppid,webankSecret,orgId);
        if (StringUtil.isNullOrBlank(accessToken)) {
            return null;
        }

        Map<String, String> params = new HashMap<>(4);
        params.put("app_id", webankAppid);
        params.put("access_token", accessToken);
        params.put("type", "SIGN");
        params.put("version", "1.0.0");
        String result = HttpClientUtil.doGet(getUrl(WebankUtil.API_TICKET), params);
        log.info("======getSignTicket======result:{},webankAppid:{},webankSecret:{}", result,webankAppid,webankSecret);
        JSONObject jsonObject = getJsonObjectIfSuccess(result);
        if (jsonObject == null) {
            return null;
        }

        JSONArray tickets = jsonObject.getJSONArray("tickets");
        if (tickets.isEmpty()) {
            redisTemplateUtil.delete(RedisKeyConstant.WKBB_BASIC_WEBANK_SIGN_TICKET+webankAppid);
            return null;
        }

        JSONObject ticket = tickets.getJSONObject(0);
        signTicket = ticket.getString("value");
        if (StringUtil.isNotEmptyIgnoreBlank(signTicket)) {
            redisTemplateUtil.set(RedisKeyConstant.WKBB_BASIC_WEBANK_SIGN_TICKET+webankAppid, signTicket, RedisKeyConstant.EXPIRATION_TIME_50);
        } else {
            redisTemplateUtil.delete(RedisKeyConstant.WKBB_BASIC_WEBANK_SIGN_TICKET+webankAppid);
        }

        //ticket被刷新，要通知到设备
        xmppService.xmppUpdateWebankSignTicket(orgId, signTicket);

        return signTicket;
    }

    @Override
    public  String getAccessToken(String webankAppid, String webankSecret, Long orgId) {


        String accessToken=null;
        accessToken = (String) redisTemplateUtil.get(RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid);
        log.info("-----------获取redis里的accessToken----------accessToken:{}",accessToken);

        if (StringUtil.isNotEmptyIgnoreBlank(accessToken)) {
            return accessToken;
        }
        log.info("\n获取微众getAccessToken............ 开始..准备开始获取分布式锁......" +RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid, orgId);
        boolean lock = false;
        int retryCount = 0;
        String result = null;
        while (!lock) {
            try {
                lock = redisTemplateUtil.tryLock(RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid+orgId, orgId.toString(), 120, TimeUnit.SECONDS);
                log.info("#################" + RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid, "加锁 ", orgId.toString());

            } catch (Exception e) {
                log.info("#################加锁失败..等待锁过期 ：" + RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid, orgId);
                e.printStackTrace();

            }

            if (lock) {//加锁成功
                try{

                    Map<String, String> params = new HashMap<>(4);
                    params.put("app_id", webankAppid);
                    params.put("secret", webankSecret);
                    params.put("grant_type", "client_credential");
                    params.put("version", "1.0.0");
                    result = HttpClientUtil.doGet(getUrl(ACCESS_TOKEN), params);
                    log.info("======getAccessToken======result:{},webankAppid:{},webankSecret:{},orgId:{}", result,webankAppid,webankSecret,orgId);
                    JSONObject jsonObject = getJsonObjectIfSuccess(result);
                    if (jsonObject == null) {
                        return null;
                    }

                    accessToken = jsonObject.getString("accessToken");

                    if (StringUtil.isNotEmptyIgnoreBlank(accessToken)) {
                        redisTemplateUtil.set(RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid, accessToken, RedisKeyConstant.EXPIRATION_TIME_50);
                    } else {
                        redisTemplateUtil.delete(RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid);
                    }

                }catch (Exception e){
                    log.error("---------获取getAccessToken异常----------result:{}", result);
                }finally {
                    log.info("#################" + RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid, "开始释放锁 ", orgId);

                    redisTemplateUtil.releaseLock(RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid+orgId, orgId.toString());

                    log.info("#################" + RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid, "释放锁成功 ", orgId);
                }

            } else {
                try {
                    retryCount++;
                    if(retryCount>20){
                        log.info("加锁失败，重试超过20次，获取微众token失败...orgId:{}" ,  orgId);
                        break;
                    }
                    log.info("等待500ms重试..." + RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid, orgId);
                    Thread.sleep(500L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        return accessToken;
    }

    private  boolean checkAccessToken(String webankAppid) {
        String accessToken = (String) redisTemplateUtil.get(RedisKeyConstant.WKBB_BASIC_WEBANK_ACCESS_TOKEN+webankAppid);
        return StringUtil.isNotEmptyIgnoreBlank(accessToken);
    }

    private  JSONObject getJsonBody(String webankAppid,String webankSecret,Long orgId) {
        String version = "1.0.0";
        String nonce = RandomStringUtils.randomAlphanumeric(32);
        String orderNo = UUID.randomUUID().toString();
        String sign = getSign(version, nonce, orderNo,webankAppid,webankSecret,orgId);
        if (StringUtil.isNullOrBlank(sign)) {
            log.warn("======Webank======{}", "获取Sign失败");
            return null;
        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("webankAppId", webankAppid);
        jsonObject.put("version", version);
        jsonObject.put("nonce", nonce);
        jsonObject.put("sign", sign);
        jsonObject.put("orderNo", orderNo);
        return jsonObject;
    }

    /**
     * 解析是否请求成功
     *
     * @param result 请求结果
     * @return 请求成功的JsonObject，不成功返回null
     */
    private  JSONObject getJsonObjectIfSuccess(String result) {
        if (StringUtil.isEmpty(result)) {
            return null;
        }

        JSONObject jsonObject = JSON.parseObject(result);
        String code = jsonObject.getString("code");
        if (StringUtil.isNullOrBlank(code)) {
            return null;
        }

        if (WebankUtil.CODE_SUCCESS.equals(code)) {
            return jsonObject;
        }

        return null;
    }

    /**
     * 获取message
     *
     * @param result 请求结果
     * @return 请求是否成功
     */
    private   String getMessage(String result) {
        if (StringUtil.isEmpty(result)) {
            return "出错";
        }

        JSONObject jsonObject = JSON.parseObject(result);
        String msg = jsonObject.getString("msg");
        if (msg == null) {
            return "失败";
        }

        return msg;
    }

    /**
     * 获取code
     *
     * @param result 请求结果
     * @return 请求是否成功
     */
    private  String getCode(String result) {
        if (StringUtil.isEmpty(result)) {
            return null;
        }

        JSONObject jsonObject = JSON.parseObject(result);
        return jsonObject.getString("code");
    }


    private  String getUrl(String action) {
        return basicConfig.getWebankUrl() + action;
    }

    private  String getTcThirdServiceUrl(String action) {
        return basicConfig.getTcThirdServiceUrl() + action;
    }

}
